﻿using System;
using System.IO;
using FtpSupport;
using System.Linq;
using System.Net;
using System.Text;
using Enyim.Caching;
using Ayatta.Contract;
using Ayatta.Common;
using System.Web.Mvc;
using Web.Base.Security;
using Web.Base.EventArgs;
using System.Web.Helpers;
using Web.Base.Extensions;
using System.Configuration;
using Web.Base.GameProxys;
using Web.Base.Components;
using Web.Base.ActionResults;
using Web.Base.Models.Game;
using Web.Base.OrderHandler;
using Ayatta.Contract.Domain;
using System.Collections.Generic;
using Ayatta.Common.Extensions;
using Ayatta.Contract.Component;
using Ayatta.Common.Configurations;

namespace Web.Base.Controllers
{
    public abstract class BaseController : Controller
    {
        protected ILogService LogService { get; private set; }
        protected IBaseService BaseService { get; private set; }
        protected IExtraService ExtraService { get; private set; }
        protected IStoreService StoreService { get; private set; }
        protected IOrderService OrderService { get; private set; }
        protected IGameService GameService { get; private set; }
        protected IAuctionService AuctionService { get; private set; }
        protected IPassportService PassportService { get; private set; }
        protected IPaymentService PaymentService { get; private set; }
        protected static IMemcachedClient MemcachedClient { get; private set; }

        protected static string DefaultUrl = WebSite.Main;
        private const string CategoryService = "CategoryService";
        protected BaseController(ILogService logService, IBaseService baseService, IExtraService extraService, IStoreService storeService, IOrderService orderService, IGameService gameService, IAuctionService auctionService, IPassportService passportService, IPaymentService paymentService, IMemcachedClient memcachedClient)
        {
            LogService = logService;
            BaseService = baseService;
            ExtraService = extraService;
            StoreService = storeService;
            OrderService = orderService;
            GameService = gameService;
            AuctionService = auctionService;
            PassportService = passportService;
            PaymentService = paymentService;
            MemcachedClient = memcachedClient;
            UserAddress.GetAreaName = GetAreaName;
        }

        protected ActionResult Captcha(string captchaKey)
        {
            return new CaptchaImageResult(captchaKey);
        }

        protected ActionResult Jsonp<T>(T data, string callback)
        {
            return new JsonpResult<T>(data, callback);
        }

        protected bool ValidateCaptcha(string captchaKey, string captchaTxt)
        {
            if (Session != null)
            {
                return Session[captchaKey].ToString() == captchaTxt.ToLower();
            }
            return false;
        }

        protected bool SendEmail(string address, EmailAccount mail, EmailTemplate template)
        {
            bool result;
            WebMail.EnableSsl = mail.EnableSsl;
            WebMail.SmtpServer = mail.Host;
            WebMail.SmtpPort = mail.Port;
            WebMail.From = mail.Email;
            WebMail.UserName = mail.Username;
            WebMail.Password = mail.Password;
            WebMail.SmtpUseDefaultCredentials = mail.UseDefaultCredentials;

            try
            {
                WebMail.Send(address, template.Subject, template.Body);
                result = true;
            }
            catch (Exception e)
            {
                result = false;
            }
            return result;
        }

        protected void SendMobileMessage(string message, params string[] mobile)
        {
            using (var client = new WebClient())
            {
                client.BaseAddress = "";
                client.QueryString.Add("username", "");
                client.DownloadString("");
            }
        }


        protected IList<ProductCategory> GetCategories(int parentId)
        {
            if (parentId < 0) return null;
            var key = string.Format(CacheKey.Store.Product.Category, parentId);
            var proxy = new ServiceClientProxy<ICategoryService>(CategoryService);
            return Put(key + parentId, () => proxy.Invoke(o => o.GetCategories(parentId)));
        }

        protected IList<CategoryProp> GetProps(int cateogryId)
        {
            if (cateogryId < 0) return null;

            var proxy = new ServiceClientProxy<ICategoryService>(CategoryService);
            var key = string.Format(CacheKey.Store.Product.CategoryProp, cateogryId);
            return Put(key + cateogryId, () => proxy.Invoke(o => o.GetProps(cateogryId)));
        }

        protected IList<CategoryPropValue> GetPropValues(int cateogryId)
        {
            if (cateogryId < 0) return null;

            var proxy = new ServiceClientProxy<ICategoryService>(CategoryService);
            var key = string.Format(CacheKey.Store.Product.CategoryPropValue, cateogryId);
            return Put(key + cateogryId, () => proxy.Invoke(o => o.GetPropValues(cateogryId)));
        }

        /// <summary>
        /// 获取用户地址库
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        protected IList<UserAddress> GetUserAddresses(int userId)
        {
            if (userId < 0) return null;
            var key = string.Format(CacheKey.Passport.User.Address, userId);
            return Put(key, () => PassportService.GetUserAddresses(userId));
        }

        /// <summary>
        /// 获取标准行政区域
        /// </summary>
        /// <returns></returns>
        protected IList<Area> GetAreas()
        {
            var key = CacheKey.Base.Areas;
            return Put(key, BaseService.GetAreas);
        }

        protected string GetAreaName(string id, IList<Area> areas)
        {
            var len = id.Length;
            string province, city;
            if (len == 2)
            {
                province = areas.First(o => o.Id == id).Name;
                return province;
            }
            if (len == 4)
            {
                var area = areas.First(o => o.Id == id);
                city = area.Name;
                province = areas.First(o => o.Id == area.ParentId).Name;
                return province + " " + city;
            }
            if (len == 6)
            {
                var area = areas.First(o => o.Id == id);
                var district = area.Name;
                area = areas.First(o => o.Id == area.ParentId);
                city = area.Name;
                area = areas.First(o => o.Id == area.ParentId);
                province = area.Name;
                return province + " " + city + " " + district;
            }
            return string.Empty;
        }

        protected Tuple<string, string, string> GetAreaNames(string id, IList<Area> areas)
        {

            var len = id.Length;
            string province, city;
            if (len == 2)
            {
                province = areas.First(o => o.Id == id).Name;
                return new Tuple<string, string, string>(province, string.Empty, string.Empty);
            }
            if (len == 4)
            {
                var area = areas.First(o => o.Id == id);
                city = area.Name;
                province = areas.First(o => o.Id == area.ParentId).Name;
                return new Tuple<string, string, string>(province, city, string.Empty);

            }
            if (len == 6)
            {
                var area = areas.First(o => o.Id == id);
                var district = area.Name;
                area = areas.First(o => o.Id == area.ParentId);
                city = area.Name;
                area = areas.First(o => o.Id == area.ParentId);
                province = area.Name;
                return new Tuple<string, string, string>(province, city, district);
            }
            return new Tuple<string, string, string>(string.Empty, string.Empty, string.Empty);
        }

        /// <summary>
        /// 获取物流公司
        /// </summary>
        /// <returns></returns>
        protected IList<LogisticsCompany> GetLogisticsCompanies()
        {
            var key = CacheKey.Base.LogisticsCompany;
            return Put(key, BaseService.GetLogisticsCompanies);
        }

        /// <summary>
        /// 获取所有游戏及其服
        /// </summary>
        /// <returns></returns>
        [NonAction]
        protected IList<Game> GetGames()
        {
            var key = CacheKey.Game.Games;
            return Put(key, () => GameService.GetGames(true));
        }
        [NonAction]
        protected T Put<T>(string key, Func<T> func) where T : class
        {
            return MemcachedClient.Put(key, func);
        }
        [NonAction]
        protected T Put<T>(string key, Func<T> func, DateTime expiresAt) where T : class
        {
            return MemcachedClient.Put(key, func, expiresAt);
        }

        /// <summary>
        /// 从Memcached缓存中移除
        /// </summary>
        /// <param name="key">Key</param>
        [NonAction]
        protected void RemoveCache(string key)
        {
            MemcachedClient.Remove(key);
        }
        [NonAction]
        protected string[] GetSkuKeys(IList<string[]> keys)
        {
            var len = keys.Count;
            if (len < 1)
            {
                return null;
            }
            if (len == 1)
            {
                return keys[0];
            }
            if (len > 1)
            {
                var first = keys[0];
                var next = keys[1];
                var array = new List<string>();
                foreach (var t in first)
                {
                    array.AddRange(next.Select(x => t + ';' + x));
                }
                if (len == 2)
                {
                    return array.ToArray();
                }
                keys.RemoveAt(0);
                keys.RemoveAt(1);
                keys[0] = array.ToArray();

                keys[0] = GetSkuKeys(keys);
            }
            return keys[0];
        }
        [NonAction]
        protected static string GenerateId(char? prefix, DateTime time, int userId, int sellerId = 0)
        {
            var sb = new StringBuilder(4);
            if (prefix != null)
            {
                sb.Append(prefix);
            }
            sb.Append(time.ToString("yyMMddHHmmssfffffff"));
            sb.Append((userId % 64).ToString("00"));
            sb.Append((sellerId % 64).ToString("00"));
            return sb.ToString();
        }
        [NonAction]
        protected Order CreateGameOrder(Game game, GameServer server, decimal amount, int userId, string nickname, string username, string ip)
        {
            var order = new Order();
            var time = DateTime.Now;
            var id = GenerateId('A', time, userId);
            order.Id = id;
            order.Category = OrderCategory.Normal;
            order.Quantity = 1;
            order.Postage = 0;
            order.SubTotal = amount;
            order.Discount = 0;
            order.Total = amount;
            order.Paid = 0;
            order.UseIntegral = 0;
            order.RealUseIntegral = 0;
            order.DonateIntegral = 0;
            order.Weight = 0;
            order.PaymentType = PaymentType.None;
            order.ShippingType = ShippingType.Virtual;
            order.PayTime = null;
            order.ConsignTime = null;
            order.EndTime = null;
            order.ExpirationTime = time.AddDays(3);
            order.ETicketExtra = string.Empty;
            order.MultipleConsign = false;
            order.Receiver = username;
            order.Phone = string.Empty;
            order.Mobile = string.Empty;
            order.AreaId = game.Id.ToString(); // 游戏Id
            order.Province = server.Id.ToString(); // 游戏区服Id
            order.City = game.Name; // 游戏名
            order.District = server.Name;//游戏区服
            order.Address = string.Empty; // 图片url
            order.PostalCode = string.Empty;
            order.HasInvoice = false;
            order.InvoiceCategory = string.Empty;
            order.InvoiceTitle = string.Empty;
            order.InvoiceContent = string.Empty;
            order.IpAddress = ip;
            order.AssociatedId = string.Empty;
            order.TraceCode = string.Empty;
            order.BuyerId = userId;
            order.BuyerNick = nickname;
            order.BuyerFlag = 0;
            order.BuyerMemo = string.Empty;
            order.BuyerMessage = string.Empty;
            order.BuyerRate = false;
            order.SellerId = 1;
            order.SellerNick = string.Empty;
            order.SellerFlag = 0;
            order.SellerMemo = string.Empty;
            order.SellerRate = false;
            order.Cancel = null;
            order.CancelReason = string.Empty;
            order.Extra = string.Empty;
            order.Status = OrderStatus.WaitBuyerPay;
            order.ModifiedOn = time;
            order.CreatedBy = username;
            order.CreatedOn = time;
            return order;
        }
        [NonAction]
        protected IGameClient GetGameClient(int gameId)
        {
            var client = GameClientFactory.Create(gameId);
            client.Updated += UpdateUserInfo;
            return client;
        }
        [NonAction]
        protected void UpdateUserInfo(object sender, EventArgs<UserInfo> e)
        {
            var user = e.Data;
            var time = DateTime.Now;
            var o = new GameUser();
            var identity = User.Identity.Identity();
            o.Guid = user.Guid;
            o.UserId = identity.Id;
            o.GameId = user.GameId;
            o.ServerId = user.ServerId;
            o.RoleName = user.RoleName;
            o.Vip = user.Vip;
            o.Level = user.Level;
            o.Currency = user.Currency;
            o.Extra = user.Extra;
            o.LastLoginOn = user.LastLoginOn ?? time;
            o.ModifiedOn = user.ModifiedOn;
            o.CreatedBy = User.Identity.Name;
            o.CreatedOn = time;
            GameService.UpdateGameUser(o);
        }

        [NonAction]
        protected void InternalOrderHandler(PayTrade payTrade)
        {
            var trade = PaymentService.GetUserTrade(payTrade.AssociatedId, payTrade.UserId);
            if (trade.Paid != trade.Amount) return;
            if (trade.Category == 0 || trade.Category == 1)
            {
                var order = OrderService.GetOrder(trade.Id, trade.UserId, true);
                foreach (var handler in OrderHandlerManager.Current.Handlers)
                {
                    handler.Process(trade, order);
                }
            }
        }

        /// <summary>
        /// ftp上传
        /// </summary>
        /// <param name="stream">文件流</param>
        /// <param name="directory">目录以/开始以/结束</param>
        /// <param name="fileName">文件名</param>
        /// <returns>返回远程文件URI</returns>
        [NonAction]
        protected SkResult<string> FtpUpload(Stream stream, string directory, string fileName)
        {
            var result = new SkResult<string>();
            var ftp = ConfigurationManager.GetSection("ftp") as FtpConfigurationSetion;
            if (ftp != null)
            {
                var file = ftp.Server + directory + fileName;
                using (var conn = new FtpConnection())
                {
                    var temp = string.Empty;
                    try
                    {
                        conn.Connect(ftp.Ip, ftp.UserName, ftp.Password);
                        foreach (var o in directory.Split('/'))
                        {
                            temp += string.Format("{0}/", o);
                            if (!conn.DirectoryExist(temp))
                            {
                                conn.CreateDirectory(temp);
                            }
                        }
                        conn.SetCurrentDirectory(directory);
                        conn.PutStream(stream, fileName);

                        result.Status = true;
                        result.Data = file;
                    }
                    catch (Exception e)
                    {
                        result.Message = e.Message;
                    }
                }
            }
            else
            {
                result.Message = "Ftp配置文件错误！";
            }
            return result;
        }

        protected string GetUserAgent()
        {
            var osVersion = "未知";

            var userAgent = Request.UserAgent ?? string.Empty;

            if (!userAgent.IsNullOrEmpty())
            {
                if (userAgent.Contains("NT 6.1"))
                {
                    osVersion = "Windows 7";
                }
                else if (userAgent.Contains("NT 6.0"))
                {
                    osVersion = "Windows Vista/Server 2008";
                }
                else if (userAgent.Contains("NT 5.2"))
                {
                    osVersion = "Windows Server 2003";
                }
                else if (userAgent.Contains("NT 5.1"))
                {
                    osVersion = "Windows XP";
                }
                else if (userAgent.Contains("NT 5"))
                {
                    osVersion = "Windows 2000";
                }
                else if (userAgent.Contains("NT 4"))
                {
                    osVersion = "Windows NT4";
                }
                else if (userAgent.Contains("Me"))
                {
                    osVersion = "Windows Me";
                }
                else if (userAgent.Contains("98"))
                {
                    osVersion = "Windows 98";
                }
                else if (userAgent.Contains("95"))
                {
                    osVersion = "Windows 95";
                }
                else if (userAgent.Contains("Mac"))
                {
                    osVersion = "Mac";
                }
                else if (userAgent.Contains("Unix"))
                {
                    osVersion = "UNIX";
                }
                else if (userAgent.Contains("Linux"))
                {
                    osVersion = "Linux";
                }
                else if (userAgent.Contains("SunOS"))
                {
                    osVersion = "SunOS";
                }
            }
            return osVersion;
        }

        /// <summary>
        ///  获取浏览器名称 版本号
        /// </summary>
        /// <returns></returns>
        protected string GetBrowser()
        {
            var browser = Request.Browser;
            return browser.Browser + browser.Version;
        }

        protected string GetIpAddress()
        {
            var result = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
            result = string.IsNullOrEmpty(result) ? Request.ServerVariables["REMOTE_ADDR"] : Request.UserHostAddress;
            return result;
        }

        protected string GetUrlReferrer()
        {
            var referrer = Request.UrlReferrer;
            return referrer != null ? referrer.ToString() : string.Empty;
        }
    }
}
